/*
 *  COPYRIGHT (c) 1989-2007.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id$
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems.h>
#include <errno.h>
#include <stdlib.h>
#include <rtems/posix/mman.h>
#include <rtems/libmmu.h>
#include <rtems/posix/mmap-internal.h>
#include <unistd.h>

/*
 *  12.2.3 Change Memory Protection, P1003.1b-1996, p. 277.
 *
 *  This is not a functional version but the SPARC backend for at least
 *  gcc 2.8.1 plus gnat 3.13p and gcc 3.0.1 require it to be there and
 *  return 0.
 *
 *  As of gcc 4.2.2, the gcc SPARC backend doesn't appear to have a
 *  way to call this for RTEMS anymore but it doesn't hurt to leave it.
 */

int mprotect(const void *addr, size_t len, int prot)
{
  rtems_memory_protection_domain* mapping = &mmap_mappings;
  rtems_memory_protection_entry* current;
  size_t  ps;
  uint32_t attr;

  /*
   * Clear errno.
   */
  errno = 0;
  /*
   * Length cannot be 0.
   */
  if ( len <= 0 ) {
    errno = EINVAL;
    return -1;
  }

  ps = sysconf( _SC_PAGESIZE ) ;
  /*addr is not a mutiple of the page size*/
  if( ((long)addr % ps != 0) || (len % ps != 0)){
    errno = EINVAL;
    return -1;
  }

  /*
   * Obtain the mmap lock. Sets errno on failure.
   */
  if ( !mmap_mappings_lock_obtain( ))
    return -1;

  /* for the private mmap, this won't happen
   * I don't consider much about the file access right
   */
  if( 0 )
    return EACCES;

  /* I do not quite understand about this error signal*/
  if( 0 )
    return  EAGAIN;

  current = (rtems_memory_protection_entry* )rtems_chain_first( &(mapping->active_mpe_chain));
  while(!rtems_chain_is_tail(&(mapping->active_mpe_chain),&current->node)){
    /*in this version, we only support the addr and len exactly same as created in mmap*/
    if( (current->region.base == addr ) && current->region.bounds == len){
      /*if the attribute is not map_private, this is not a page mapped by mmap
       * so return error*/
      if( (current->permissions & RTEMS_MEMORY_PROTECTION_MAP_PRIVATE)== 0){
        errno = ENOMEM;
        mmap_mappings_lock_release( );
        return -1;
      }
        
      /* FIXME: just use the MEMORY_PROTECTION defines?  */
      attr = current->permissions;
      attr &= ~( RTEMS_MEMORY_PROTECTION_WRITE_PERMISSION | RTEMS_MEMORY_PROTECTION_READ_PERMISSION );
      attr |= prot & (PROT_READ|PROT_WRITE);
     
      if(rtems_memory_protection_verify_permission(attr) != RTEMS_SUCCESSFUL){
        errno = ENOTSUP;
        mmap_mappings_lock_release( );
        return -1;
      }

      current->permissions = attr;
      rtems_memory_protection_install_entry(current);
      mmap_mappings_lock_release( );
      return 0;
    }
    current = (rtems_memory_protection_entry* )rtems_chain_next(&current->node);
  }

  mmap_mappings_lock_release( );
  errno = ENOMEM;
  return -1;
}
